package com.justdoit.facedemo.utils;

import com.arcsoft.face.*;
import com.arcsoft.face.enums.CompareModel;
import com.arcsoft.face.enums.DetectModel;
import com.arcsoft.face.enums.ErrorInfo;
import com.arcsoft.face.toolkit.ImageInfoEx;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * 封装好的人脸识别类，直接调用即可
 */
@Component
@Data
public class ArcFaceWorker {

    private final FaceEngine faceEngine;

    public ArcFaceWorker(FaceEngine faceEngine) {
        this.faceEngine = faceEngine;
    }

    /**
     * 人脸检测
     *
     * @return 返回人脸信息集合
     */
    public List<FaceInfo> detectFace(ImageInfoEx imageInfoEx) {

        if (imageInfoEx == null)  return null;

        // 用来保存结果的list
        List<FaceInfo> faceInfoList = new ArrayList<FaceInfo>();

        // 进行人脸识别，成功返回ErrorInfo.MOK
        int i = faceEngine.detectFaces(imageInfoEx, DetectModel.ASF_DETECT_MODEL_RGB, faceInfoList);

        // 自定义方法，进行判断，是否识别成功，不成功抛异常
        checkEngineResult(i, ErrorInfo.MOK.getValue(), "人脸检测失败");

        // 如果识别成功了，就返回保存结果的list
        return faceInfoList;

    }

    /**
     * 特征提取
     *
     * @param faceInfoList  list 人脸信息集合
     * @param imageInfoEx   二次包装类
     * @return  返回人脸特征包装类
     */
    public FaceFeature extractFaceFeature(
            List<FaceInfo> faceInfoList, ImageInfoEx imageInfoEx) {

        if (faceInfoList.size() < 1 || imageInfoEx == null) return null;

        // 创建用来保存人脸特征的包装类
        FaceFeature faceFeature = new FaceFeature();

        // 进行人脸特征提取
        int i = faceEngine.extractFaceFeature(imageInfoEx, faceInfoList.get(0), faceFeature);

        // 使用自定义方法，判断特征提取是否成功
        checkEngineResult(i, ErrorInfo.MOK.getValue(), "人脸特征提取失败");

        // 返回特征包装类
        return faceFeature;
    }


    /**
     * 人脸对比
     *
     * @param target  要识别的目标对象
     * @param source  用来对比的资源
     * @param compareModel  用来对比的算法模型
     * @return   返回一个 FaceSimilar 包装对象，里面有一个 float 类型的值，名为 score 用来保存相似值
     */
    public FaceSimilar compareFaceFeature(
            FaceFeature target, FaceFeature source, CompareModel compareModel) {

        // 创建相似度包装类
        FaceSimilar faceSimilar = new FaceSimilar();

        // 进行对比
        int i = faceEngine.compareFaceFeature(target, source, compareModel, faceSimilar);

        // 使用自定义方法进行结果校验
        checkEngineResult(i, ErrorInfo.MOK.getValue(), "人脸特征对比失败");

        // 返回相似度包装类
        return faceSimilar;
    }

    /**
     * 错误检测
     *
     * @param errorCode  状态码
     * @param sourceCode 成功的状态码
     * @param errMsg     错误提示信息
     */
    private void checkEngineResult(int errorCode, int sourceCode, String errMsg) {
        if (errorCode != sourceCode)
            throw new RuntimeException(errMsg);
    }
}

